package com.dbflow5.processor.definition;

import com.dbflow5.annotation.Column;
import com.dbflow5.annotation.ColumnMap;
import com.dbflow5.annotation.ConflictAction;
import com.dbflow5.annotation.PrimaryKey;
import com.dbflow5.processor.ProcessorManager;
import com.dbflow5.processor.definition.column.ColumnDefinition;
import com.dbflow5.processor.definition.column.ReferenceColumnDefinition;
import com.dbflow5.processor.utils.ElementUtility;
import javax.lang.model.element.Element;

/**
 * Description: Generates a [ColumnDefinition] or [ReferenceColumnDefinition] based on the [Element]
 * passed into the [generate] method.
 */
public class BasicColumnGenerator {
    private ProcessorManager manager;

    public BasicColumnGenerator(ProcessorManager manager) {
        this.manager = manager;
    }

    /**
     * Generates a [ColumnDefinition]. If null, there is a field that is package private not in the same package that we
     * did not generate code for to access.
     *
     * @param element element
     * @param entityDefinition entityDefinition
     * @return ColumnDefinition
     */
    public ColumnDefinition generate(Element element, EntityDefinition entityDefinition) {
        boolean isColumnMap = element.getAnnotation(ColumnMap.class) != null;
        boolean isPackagePrivate = ElementUtility.isPackagePrivate(element);
        boolean isPackagePrivateNotInSamePackage = isPackagePrivate && !ElementUtility.isInSamePackage(manager, element, entityDefinition.element);

        if (checkInheritancePackagePrivate(isPackagePrivateNotInSamePackage, element)) return null;

        if (isColumnMap) {
            return new ReferenceColumnDefinition(element.getAnnotation(ColumnMap.class), manager, entityDefinition, element, isPackagePrivateNotInSamePackage);
        } else {
            return new ColumnDefinition(manager, element, entityDefinition, isPackagePrivateNotInSamePackage, element.getAnnotation(Column.class),
                    element.getAnnotation(PrimaryKey.class), ConflictAction.NONE);
        }
    }

    /**
     * Do not support inheritance on package private fields without having ability to generate code for it in
     * same package.
     *
     * @param isPackagePrivateNotInSamePackage isPackagePrivateNotInSamePackage
     * @param element element
     * @return check inheritance on package private fields
     */
    private boolean checkInheritancePackagePrivate(boolean isPackagePrivateNotInSamePackage, Element element) {
        if (isPackagePrivateNotInSamePackage && !manager.elementBelongsInTable(element)) {
            manager.logError("Package private inheritance on non-table/querymodel/view " +
                "is not supported without a @InheritedColumn annotation." +
                " Make $element from ${element.enclosingElement} public or private.");
            return true;
        }
        return false;
    }
}